use core::ptr::copy_nonoverlapping;

use crate::{encode2::ProtoEncode2, frame::Proto, proto::{END, HEAD0, HEAD1, MIN_LEN}};

pub unsafe fn xor_sum(ptr: *const u8, len: usize) -> u8 {
    let mut s = 0;
    for i in 0..len {
        s = s ^ *ptr.add(i);
    }
    s
}

pub trait ToProtoBytes2 {
    unsafe fn to_bytes(self, ptr: *mut u8) -> usize;
}

impl ToProtoBytes2 for &[u8] {
    
    #[inline(always)]
    unsafe fn to_bytes(self, ptr: *mut u8) -> usize {
        let len = self.len();
        copy_nonoverlapping(self.as_ptr(), ptr, len);
        len
    }
}

#[cfg(not(feature = "address_proto"))]
impl <T: ProtoEncode2> ToProtoBytes2 for Proto<T> {

    unsafe fn to_bytes(self, ptr: *mut u8) -> usize {
        *ptr = HEAD0;
        *ptr.add(1) = HEAD1;
      //  *ptr.add(2) = 0;
        *ptr.add(3) = self.ty;
        *ptr.add(4) = self.seq;
        let n = self.body.encode(ptr.add(5));
        let s = xor_sum(ptr.add(3), n + 2);
        *ptr.add(2) = (n + MIN_LEN) as u8;
        *ptr.add(5 + n) = s;
        *ptr.add(6 + n) = END;
        n + MIN_LEN
    }
}

#[cfg(feature = "address_proto")]
impl <T: ProtoEncode2> ToProtoBytes2 for Proto<T> {

    unsafe fn to_bytes(self, ptr: *mut u8) -> usize {
        *ptr = HEAD0;
        *ptr.add(1) = HEAD1;
      //  *ptr.add(2) = 0;
        *ptr.add(3) = self.ty;
        *ptr.add(4) = self.seq;
        *ptr.add(5) = self.src;
        *ptr.add(6) = self.dst;
        let n = self.body.encode(ptr.add(7));
        let s = xor_sum(ptr.add(3), n + 4);
        *ptr.add(2) = (n + MIN_LEN) as u8;
        *ptr.add(7 + n) = s;
        *ptr.add(8 + n) = END;
        n + MIN_LEN
    }
}


